#!/bin/bash

# the mode format is : 17.720x576.50 (the drm number + resolution + hz).
# the idea is to detect at setMode that the tv changed (ie, don't set mode 17 if on the tv i configured, 17 is 640x480 and that on the new one, this is a different resolution)
# at the same time, we keep in /var/run/drmMode the single drm number so that emulators patches remain simple

f_usage() {
    echo "${0} listModes" >&2
    echo "${0} setMode <MODE>" >&2
    echo "${0} currentMode" >&2
    echo "${0} currentResolution" >&2
    echo "${0} listOutputs" >&2
    echo "${0} setOutput <output>" >&2
    echo "${0} minTomaxResolution" >&2
    echo "${0} minTomaxResolution-secure" >&2
    echo "${0} getDisplayMode" >&2
}

# use for syntax only
PSCREEN=
if test "${1}" = "--screen"
then
    shift
    PSCREEN=$1
    shift
fi

ACTION=$1
shift

if test -z "${ACTION}"
then
    f_usage
    exit 1
fi

# assume one card only for the moment
# we should add the card...
f_getConnectors() {
    for GPU in /dev/dri/card*
    do
	batocera-drminfo "${GPU}" 2>/dev/null
    done | cut -d '.' -f 1 | sort -u
}

f_checkVals() {
    # check that the conn is available
    CONN=$(cat /var/run/drmConn 2>/dev/null)
    if echo "${CONN}" | grep -qE '^[0-9]+$'
    then
	if ! f_getConnectors | grep -qE "^${CONN}$"
	then
	    echo f_getConnectors | head -1 > /var/run/drmMode # take the first connector
	fi
    else
	f_getConnectors | head -1 > /var/run/drmConn # take the first connector
	echo 0 > /var/run/drmMode
    fi
}

f_listModes() {
    DRMCONN=$(cat /var/run/drmConn)

    if test "${1}" = "all"
    then
	echo "max-1920x1080:maximum 1920x1080"
	echo "max-640x480:maximum 640x480"
    fi
    for GPU in /dev/dri/card*
    do
	batocera-drminfo "${GPU}" "${1}" 2>/dev/null | grep -E "^${DRMCONN}\." |  sed -e s+"^\([0-9]*\)\.\([0-9]*\):\([^ ]*\) \([0-9]*\)x\([0-9]*\) \([0-9]*\)\(Hz .*\)$"+"\1.\2.\4x\5.\6:\3 \4x\5 \6\7"+
    done
}

f_currentResolution() {
    DRMCONN=$(cat /var/run/drmConn)
    DRMMODE=$(cat /var/run/drmMode)
    f_listModes "all" | grep -E "^${DRMCONN}\.${DRMMODE}\." | head -1 | sed -e s+"^[^:]*:[^ ]* \([0-9]*x[0-9]*\) .*$"+"\1"+
}

f_minTomaxResolution() {
	# minimize resolution because of 4K tv
	MWIDTH=$(echo "$1"x | tr -d [[:blank:]] | cut -dx -f1) # the final added x is for compatibility with v29
	MHEIGHT=$(echo "$1"x | tr -d [[:blank:]] | cut -dx -f2)

	if test -n "$MWIDTH" -a -n "$MHEIGHT" -a "$MWIDTH" != 0 -a "$MHEIGHT" != 0; then
		MAXWIDTH="$MWIDTH"
		MAXHEIGHT="$MHEIGHT"
	else
		MAXWIDTH=1920
		MAXHEIGHT=1080
	fi
	# if current resolution is ok, keep it
	read CURRENTWIDTH CURRENTHEIGHT <<< $(f_currentResolution | sed -e s+"^\([0-9]*\)x\([0-9]*\)$"+"\1 \2"+)

	if test "${CURRENTWIDTH}" -le "${MAXWIDTH}" -a "${CURRENTHEIGHT}" -le "${MAXHEIGHT}"
	then
	    # hack for the rpi4 => need to avoid resolution 1360x768 (see batocera-drminfo-no-1360x768.c)
	    # i don't like this hack, but this is to avoid a duplication of the file for the rpi4 #specific issue
	    ARCH=$(cat /usr/share/batocera/batocera.arch)
	    if ! test "${ARCH}" = "bcm2711" -a "${CURRENTWIDTH}" = 1360 -a "${CURRENTHEIGHT}" = 768
	    then
		exit 0
	    fi
	fi

	# select a new one
	# select the first one valid
	# is it the best ? or should we loop to search the first with the same ratio ?
	# Highest resolution first, but list [p]rogressive before [i]nterlaced (p is omitted by default)
	f_listModes | sed -e "/i)$/!"s+")$"+"p)"+ -e s+"^\([^:]*\):[^ ]* \([0-9]*x[0-9]*\) \([0-9]*\)Hz (\(.*\))$"+"\2_\3_\4:\1:\2"+ | sort -nr | sed -e "s/_[0-9]*x[0-9]*[pi]//" |
            while IFS=':\n' read SORTSTR SUGGMODE SUGGRESOLUTION
            do
		SUGGWIDTH=$(echo "${SUGGRESOLUTION}" | cut -d x -f 1)
		SUGGHEIGHT=$(echo "${SUGGRESOLUTION}" | cut -d x -f 2)

		if test "${SUGGWIDTH}" -le "${MAXWIDTH}" -a "${SUGGHEIGHT}" -le "${MAXHEIGHT}"
		then
                    echo "${SUGGMODE}" | cut -d "." -f 2 > /var/run/drmMode
                    exit 0
		fi
            done
}

case "${ACTION}" in
    "listModes")
	f_checkVals
	f_listModes "all"
	;;
    "setMode")
	MODE=$1

	f_checkVals

	if echo "${MODE}" | grep -qE 'max-' # special max-widthxheight
	then
	    SPMODE=$(echo "${MODE}" | sed -e s+"^max-"++)
	    f_minTomaxResolution "${SPMODE}"
	else # normal mode
	    # check that the mode is valid
	    if f_listModes "all" | grep -qE "^${MODE}:"
	    then
		echo "${MODE}" | cut -d "." -f 2 > /var/run/drmMode
	    else
		echo "invalid mode ${MODE}" >&2
	    fi
	fi
	;;
    "currentMode")
	f_checkVals
	DRMCONN=$(cat /var/run/drmConn)
	DRMMODE=$(cat /var/run/drmMode)
	f_listModes "all" | grep -E "^${DRMCONN}\.${DRMMODE}\." | cut -d ":" -f 1
	;;
    "currentResolution")
	f_checkVals
	f_currentResolution
	;;
    "listOutputs")
	for GPU in /dev/dri/card*
	do
	    batocera-drminfo "${GPU}" "${1}" 2>/dev/null | sed -e s+"^\([0-9]*\)\.\([0-9]*\):\([^ ]*\) \([0-9]*\)x\([0-9]*\) \([0-9]*\)\(Hz .*\)$"+"\1 - \3"+ | sort -u
	done
	;;
    "currentOutput")
       for GPU in /dev/dri/card*
       do
           batocera-drminfo "${GPU}" "current" 2>/dev/null | grep -E '^0.0:' | sed -e s+"^0.0:\([^ ]*\) .*$"+"\1"+
       done | head -1
       ;;
    "setOutput")
	MODE=$1
	if test "${MODE}" != ""
	   then
	       echo "${MODE}" | sed -e s+"^\([0-9]*\) .*"+"\1"+ > /var/run/drmConn
	       echo 0 > /var/run/drmMode # reset the drmMode
	fi
	f_checkVals
	;;
    "minTomaxResolution" | "minTomaxResolution-secure")
	f_checkVals
	f_minTomaxResolution "$1"
        ;;
    "supportSystemRotation")
	exit 1
	;;
    "supportSystemReflection")
	exit 1
        ;;
    "setRotation")
	# no possible rotation
	exit 1
	;;
    "getDisplayMode")
        echo "drm"
        ;;
    *)
        f_usage
        ;;
esac

if command -v batocera-resolution-post >/dev/null
then
    batocera-resolution-post "${ACTION}" "${1}"
fi

exit 0
